package com.easy.generator.java;


import com.easy.bean.Member;
import com.easy.generator.Easy;
import com.easy.generator.annotation.EasyCascade;
import com.easy.generator.annotation.EasyField;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

public class ControllerGenerator {

    public static void generate() throws Exception {
        // 获取类加载器
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // 扫描包下的所有类
        Set<Class<?>> classes = Easy.scanClasses(Easy.BEAN_PACKAGE, classLoader);
        // 为每个实体类生成Controller
        for (Class<?> clazz : classes) {
            if (Easy.isEntityClass(clazz)) {
                generateControllerFile(clazz);
            }
        }
    }


    private static void generateControllerFile(Class<?> entityClass) throws IOException {
        String className = entityClass.getSimpleName();
        String controllerName = className + "Controller";
        String serviceName = className + "Service";
        String classLowerName = String.valueOf(className.charAt(0)).toLowerCase() + className.substring(1);
        String serviceVarName = classLowerName + "Service";

        File dir = new File(Easy.PROJECT_ABSOLUTE_URL + "/src/main/java/" + Easy.CONTROLLER_PACKAGE.replace('.', '/'));
        if (!dir.exists()) {
            dir.mkdirs();
        }

        File file = new File(dir, controllerName + ".java");
        try (PrintWriter out = new PrintWriter(file)) {
            String classText = "package " + Easy.CONTROLLER_PACKAGE + ";\n" +
                    "\n" +
                    "import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\n" +
                    "import com.baomidou.mybatisplus.extension.plugins.pagination.Page;\n" +
                    "\n" +
                    "import org.springframework.web.bind.annotation.*;\n" +
                    "import org.springframework.beans.factory.annotation.*;\n" +
                    "import com.github.yulichang.wrapper.MPJLambdaWrapper;\n"+
                    "\n" +
                    "import " + Easy.BEAN_PACKAGE + ".*;\n" +
                    "import " + Easy.SERVICE_PACKAGE + ".*;\n" +
                    "import " + Easy.UTIL_PACKAGE + ".*;\n" +
                    "import " + Easy.EXCEPTION_PACKAGE + ".*;\n" +
                    "\n" +
                    "@RestController\n" +
                    "@RequestMapping(\"/" + classLowerName + "\")\n" +
                    "@CrossOrigin\n" +
                    "public class " + controllerName + " {\n" +
                    "\n" +
                    "    @Autowired\n" +
                    "    private " + serviceName + " " + serviceVarName + ";\n" +
                    "\n";
            out.println(classText);
            // 生成CRUD方法
            generateCrudMethods(out, className, serviceVarName, entityClass);
            out.println("}");
        }
    }

    private static void generateCrudMethods(PrintWriter out, String className, String serviceVarName, Class clazz) {
        String varName = String.valueOf(className.charAt(0)).toLowerCase() + className.substring(1);
        Field[] fields = clazz.getDeclaredFields();
        StringBuilder strb = new StringBuilder();
        strb.append("\n");
        strb.append("    @GetMapping\n");
        strb.append("    public Result getAll() {\n");
        strb.append("        return Result.success(" + serviceVarName + ".list());\n");
        strb.append("    }\n");
        strb.append("\n");
        strb.append("    @GetMapping(\"page\")\n");
        strb.append("    public Result getPage(Page page, @RequestParam(name = \"search\", required = false) String searchtext) {\n");
        strb.append("         MPJLambdaWrapper<"+className+"> wrapper = new MPJLambdaWrapper<>();\n");
        for (Field field : fields) {
            if (field.isAnnotationPresent(EasyCascade.class)) {
                //当前正在解析属性的名称
                String currentFieldName = field.getName();
                //当前正在解析属性对应的get方法名称
                String currentFieldGetMthodName = "get" + (currentFieldName.charAt(0) + "").toUpperCase() + currentFieldName.substring(1);
                //获取当前属性EasyCascade注解
                EasyCascade cascade = field.getAnnotation(EasyCascade.class);
                //注解中标注的级联类也是当前属性的类型
                Class cascadeClass = cascade.cascade();
                //获取级联类名称
                String cascadeClassName = cascadeClass.getSimpleName();
                //关联类中的关联字段
                String fieldName = cascade.field();
                //当前类中外键字段名称
                String cascadeFieldName = cascade.cascadeField();
                //当前类中关联字段的get方法名称
                String cascadeFieldGetMthodName = "get" + (cascadeFieldName.charAt(0) + "").toUpperCase() + cascadeFieldName.substring(1);
                strb.append("        wrapper.selectAssociation(" + cascadeClassName + ".class," + className + "::" + currentFieldGetMthodName + ");\n");
                strb.append("        wrapper.rightJoin(" + cascadeClassName + ".class, " + cascadeClassName + "::getId, " + className + "::" + cascadeFieldGetMthodName + ");\n");
            }
        }
        strb.append("        if (searchtext != null && !searchtext.isEmpty()) {\n");
        int flag = 0;
        for (Field field : fields) {
            if (field.isAnnotationPresent(EasyField.class)) {
                if (field.getAnnotation(EasyField.class).search()) {
                    if (field.isAnnotationPresent(EasyCascade.class)) {
                        EasyCascade cascade = field.getAnnotation(EasyCascade.class);
                        Class cascadeClass = cascade.cascade();
                        String cascadeClassName = cascadeClass.getSimpleName();
                        String showFieldName = cascade.showField();
                        if (flag == 1) {
                            strb.append("            wrapper.or();\n");
                        }
                        flag = 1;
                        String showFieldGetMthodName = "get" + (showFieldName.charAt(0) + "").toUpperCase() + showFieldName.substring(1);
                        strb.append("            wrapper.like(" + cascadeClassName + "::" + showFieldGetMthodName + ", searchtext);\n");
                    } else {
                        String name = field.getName();
                        if (flag == 1) {
                            strb.append("            wrapper.or();\n");
                        }
                        flag = 1;
                        strb.append("            wrapper.like(\"" + name + "\", searchtext);\n");
                    }
                }
            }
        }
        strb.append("        }\n");
        strb.append("        return Result.success(" + serviceVarName + ".page(page, wrapper));\n");
        strb.append("    }");
        strb.append("\n");
        strb.append("    @GetMapping(\"/{id}\")\n");
        strb.append("    public Result getById(@PathVariable(\"id\") Long id) {\n");
        strb.append("        return Result.success(" + serviceVarName + ".getById(id));\n");
        strb.append("    }\n");
        strb.append("\n");
        strb.append("    @PostMapping\n");
        strb.append("    public Result create(@RequestBody " + className + " entity) {\n");
        strb.append("        return Result.success(\"数据已经存储\"," + serviceVarName + ".save(entity));\n");
        strb.append("    }\n");
        strb.append("\n");
        strb.append("    @PutMapping\n");
        strb.append("    public Result update( @RequestBody " + className + " entity) {\n");
        strb.append("        return Result.success(\"数据已经更新\"," + serviceVarName + ".saveOrUpdate(entity));\n");
        strb.append("    }\n");
        strb.append("\n");
        strb.append("    @DeleteMapping(\"/{id}\")\n");
        strb.append("    public Result delete(@PathVariable(\"id\") Long id) {\n");
        strb.append("        return Result.success(\"数据已经删除\"," + serviceVarName + ".removeById(id));\n");
        strb.append("    }");
        out.println(strb.toString());
    }
}
